package board;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import util.Util;
import beans.ChessPiece;
import beans.Color;
import beans.Move;
import beans.Piece;
import beans.Position;

/**
 * This class represents a chess board with a concrete position, it also has the necessary
 * methods to manage the board, to retrieve the pieces that have access to a concrete square,
 * it also provides information about checks and check-mates.
 * 
 * @author Josep M Sobrepere
 *
 */
public class Board implements Serializable{
	/**
	 * This array represents the squares of the board.
	 */
	private Piece[][] board = new Piece[8][8];
	/**
	 * 
	 */
	private Move lastMove;
	
	private int whiteCastling;
	private int blackCastling;
	private int halfMoves;
	private int fullMove;
	private int enPassant;
	private Color turn;
	
	
	
	/**
	 * This constructor initiates a board in its initial position.
	 */
	public Board(){
		for (int x=0;x<8;x++){
			for (int y=0;y<8;y++){
				this.setPiece(x, y, null);				
			}			
		}
		for(int i=0;i<8;i++){
			this.setPiece(i,1, new Piece(Color.WHITE, ChessPiece.PAWN));
			this.setPiece(i,6, new Piece(Color.BLACK, ChessPiece.PAWN));
		}	
		initialRow(Color.WHITE);
		initialRow(Color.BLACK);
		
		this.whiteCastling=3;
		this.blackCastling=3;
		this.fullMove=0;
		this.halfMoves=0;
		this.enPassant=-1;
		this.turn=Color.WHITE;		
		this.lastMove=null;
	}
	
	/**
	 * This constructor initializes the board with the position that is recieved by paramenter
	 * 
	 * @param board initial position 
	 * @param whiteCastling indicates the rights of castling for white
	 * @param blackCastling indicates the rights of castling for black
	 * @param halfMoves number of halfMoves that have been done to reach that position
	 * @param fullMove the fullMove number
	 * @param enPassant indicates if there is a pawn en passant
	 * @param turn side to move
	 */
	public Board(Piece[][] board, int whiteCastling, int blackCastling, int halfMoves, int fullMove, int enPassant, Color turn){
		this.board= board;
		this.lastMove=null;
		this.whiteCastling=whiteCastling;
		this.whiteCastling=blackCastling;
		this.halfMoves= halfMoves;
		this.fullMove=fullMove;
		this.enPassant=enPassant;
		this.turn=turn;
	}
	
	
	/**
	 * Simple function used to initialize the first and the 8th row. 
	 * 
	 * @param color indicates if we want to initialize the 1st or the 8th row.
	 */
	private void initialRow(Color color){
		int row = (color==Color.WHITE)?0:7;
		this.setPiece(0,row, new Piece(color,ChessPiece.ROOK));
		this.setPiece(1,row, new Piece(color,ChessPiece.KNIGHT));
		this.setPiece(2,row, new Piece(color,ChessPiece.BISHOP));
		this.setPiece(3,row, new Piece(color,ChessPiece.QUEEN));
		this.setPiece(4,row, new Piece(color,ChessPiece.KING));
		this.setPiece(5,row, new Piece(color,ChessPiece.BISHOP));
		this.setPiece(6,row, new Piece(color,ChessPiece.KNIGHT));
		this.setPiece(7,row, new Piece(color,ChessPiece.ROOK));
	}
	
	
	/**
	 * Function used to register a legal move in the board.
	 * 
	 * @param move move to be registered in the board
	 */
	public void registerMove(Move move){	
		Piece piece = this.getPiece(move.getFrom());		
		Piece pieceTo = this.getPiece(move.getTo());		
		//comprovació de captura al peo en passant
		if(piece.getKind()== ChessPiece.PAWN && move.getFrom().getX()!=move.getTo().getX() && pieceTo==null){
			int i = (piece.getColor()==Color.WHITE)?-1:1;
			this.setPiece(move.getTo().getX(),move.getTo().getY()+i, null);			
		}		
		//cas de coronar
		if(move.getPiecePromotion()!=null){
			piece.setKind(move.getPiecePromotion());
		}		
		this.setPiece(move.getTo(), piece);
		this.setPiece(move.getFrom(), null);
		//enroc
		if(piece.getKind()==ChessPiece.KING && Math.abs(move.getTo().getX()-move.getFrom().getX())==2){
			if(move.getTo().getX()==6){
				this.setPiece(5, move.getTo().getY(), this.getPiece(7, move.getTo().getY()));
				this.setPiece(7, move.getTo().getY(), null);
				if (!move.getShortAlgebraicNotation().startsWith("O-O"))					
					move.setShortAlgebraicNotation("O-O");
			}
			if(move.getTo().getX()==2){
				this.setPiece(3, move.getTo().getY(), this.getPiece(0, move.getTo().getY()));
				this.setPiece(0, move.getTo().getY(), null);
				if (!move.getShortAlgebraicNotation().startsWith("O-O"))
					move.setShortAlgebraicNotation("O-O-O");
			}
		}
		
		if(piece.getColor()==Color.WHITE && this.whiteCastling>0){
			if(piece.getKind()== ChessPiece.KING){
				this.whiteCastling=0;
			}else if (piece.getKind()==ChessPiece.ROOK){				
				if(this.whiteCastling==3){
					if(move.getFrom().getX()==0){
						this.whiteCastling=1;
					}else if (move.getFrom().getX()==7){
						this.whiteCastling=2;
					}
				}else if(this.whiteCastling==2 && move.getFrom().getX()==0){					
						this.whiteCastling=0;
				}else if(this.whiteCastling==1 && move.getFrom().getX()==7){					
						this.whiteCastling=0;
				}
			}			
		}else if(piece.getColor()==Color.BLACK && this.blackCastling>0){
			if(piece.getKind()== ChessPiece.KING){
				this.blackCastling=0;
			}else if (piece.getKind()==ChessPiece.ROOK){				
				if(this.blackCastling==3){
					if(move.getFrom().getX()==0){
						this.blackCastling=1;
					}else if (move.getFrom().getX()==7){
						this.blackCastling=2;
					}
				}else if(this.blackCastling==2 && move.getFrom().getX()==0){					
						this.blackCastling=0;
				}else if(this.blackCastling==1 && move.getFrom().getX()==7){					
						this.blackCastling=0;
				}
			}
		}
		
		if(piece.getKind()== ChessPiece.PAWN || pieceTo!=null){
			this.halfMoves=0;
		}else{
			this.halfMoves++;
		}		
		if(piece.getColor()== Color.BLACK){
			this.turn=Color.WHITE;
		}else{
			this.turn=Color.BLACK;
		}
		
		if(piece.getKind()== ChessPiece.PAWN && Math.abs(move.getFrom().getY()-move.getTo().getY())==2){
			this.enPassant=move.getFrom().getX();
		}else{
			this.enPassant=-1;
		}
		
		this.fullMove= move.getNumber();		
		move.setPreviousMove(this.lastMove);
		if(this.lastMove!=null)
			this.lastMove.setNextMove(move);
		this.lastMove=move;
	}
	
	/**
	 * This function can be useful when parsing a move from short algebraic notation and wanting to 
	 * know what is the position from where the move is been made. For example, if we are trying to
	 * parse a move such Nf3 we will need to know from what square that knight is been moved, and this
	 * function will provide us that information. 
	 * 
	 * @param kind the kind of piece that has been moved. 
	 * @param to the position where it has been moved.
	 * @param turn what side made that move (black or white)
	 * @param help in case there is move than one piece that can access to that position the algebraic notation
	 * will provide 1 or 2 characters that will help us to know what piece has been moved, those characters are
	 * the ones that are expected to be in this parameter.
	 * @return The position from where the piece has been moved.
	 */
	public Position searchPositionPiece(ChessPiece kind, Position to, Color turn, String help){
		if(help==null){
			return getPiecesWithAccesToPosition(to, kind, turn,-1,true)[0];			
		}else if(help.length()==1){
			int helpX=-1;
			int helpY=-1;
			Position positions[]=getPiecesWithAccesToPosition(to, kind, turn,-1,true); 
			if(help != null){
				char h = help.charAt(0);
				if(h>96){					
					helpX=h-97;
					for(int i=0;i<positions.length;i++){
						if(positions[i].getX()==helpX)
							return positions[i];
					}
				}else{
					helpY=h-49;
					for(int i=0;i<positions.length;i++){
						if(positions[i].getY()==helpY)
							return positions[i];
					}
				}
			}			
		}else{
			return Util.getPositionFromStr(help);
		}
		return null;	
	}	
	
	/**
	 * Critical function used to get the position of the pieces that have acces to a concrete square. 
	 * 
	 * @param pos Position where we are checking the access to
	 * @param kind if searching for a concrete kind of piece with access to that square this kind must be specified here, otherwise just pass null value.
	 * @param color this parameter can not be null, the color of the pieces that can have acces to the square.
	 * @param xEnPassant if in the last move there was a pawn on passant, the column of the pawn must be specified here, otherwise -1 value will be expected
	 * @param checkPin if we want to discard the pieces that are under an absolute pin (meaning that moving that piece will leave the king under check) pass true, otherwise pass false. 
	 * @return an array containing the positions where the pieces with acces to that square are (according with the given parameters).
	 */
	public Position[] getPiecesWithAccesToPosition(Position pos, ChessPiece kind, Color color, int xEnPassant,boolean checkPin){		
		Position positions[];
		if(kind==null){
			Position allPositions[][] = new Position[6][];			              
			allPositions[0] = pieceSearch(true,pos,ChessPiece.ROOK,color, new int[]{0,0,1,-1}, new int[]{-1,1,0,0},checkPin);			
			allPositions[1] = pieceSearch(false,pos,ChessPiece.KNIGHT,color,  new int[]{1,1,-1,-1,2,2,-2,-2},  new int[]{2,-2,2,-2,1,-1,1,-1},checkPin);			
			allPositions[2] = pieceSearch(true,pos,ChessPiece.BISHOP,color, new int[]{1,1,-1,-1}, new int[]{1,-1,1,-1},checkPin);			
			allPositions[3] = pieceSearch(true,pos,ChessPiece.QUEEN,color, new int[]{1,1,-1,-1,0,0,1,-1}, new int[]{1,-1,1,-1,-1,1,0,0},checkPin);			
			allPositions[4]= pieceSearch(false,pos,ChessPiece.KING,color, new int[]{0,0,1,1,1,-1,-1,-1}, new int[]{1,-1,0,1,-1,0,1,-1},checkPin);
			allPositions[5]=  pawnSearch(pos, color, xEnPassant,checkPin);
			
			positions = new  Position[allPositions[0].length+allPositions[1].length+allPositions[2].length+allPositions[3].length+allPositions[4].length+allPositions[5].length];
			int i=0;
			for(int z=0;z<6;z++){
				for(int y=0;y<allPositions[z].length;y++){
					positions[i]=allPositions[z][y];
					i++;
				}
			}
			return positions;			
		}
		switch (kind){
			case ROOK :
				positions = pieceSearch(true,pos,kind,color, new int[]{0,0,1,-1}, new int[]{-1,1,0,0},checkPin);
				return positions;			
			case KNIGHT :
				positions = pieceSearch(false,pos,kind,color,  new int[]{1,1,-1,-1,2,2,-2,-2},  new int[]{2,-2,2,-2,1,-1,1,-1},checkPin);
				return positions;
			case BISHOP :
				positions = pieceSearch(true,pos,kind,color, new int[]{1,1,-1,-1}, new int[]{1,-1,1,-1},checkPin);
				return positions;
			case QUEEN :
				positions = pieceSearch(true,pos,kind,color, new int[]{1,1,-1,-1,0,0,1,-1}, new int[]{1,-1,1,-1,-1,1,0,0},checkPin);
				return positions;
			case KING :
				positions = pieceSearch(false,pos,kind,color, new int[]{0,0,1,1,1,-1,-1,-1}, new int[]{1,-1,0,1,-1,0,1,-1},checkPin);
				return positions;
			case PAWN :
				positions =  pawnSearch(pos, color, xEnPassant,checkPin);
				return positions;
		}		
		return null;
	}
	
	
	
	
	/**
	 * Critical function used to retrieve the pieces with access into a concrete square 
	 * 
	 * @param recursive if the search is recursive (for bishops, rooks and queens must be true, for the rest of pieces must be false)
	 * @param position square where we are searching the access to 
	 * @param kind kind of piece that we are looking for with acces to that square (this value can not be null)
	 * @param color color of the pieces taht we are searching (this value can not be null)
	 * @param yIncrement array containing the possible y increment of that piece 
	 * @param xIncrement array containing the possible x increment of that piece
	 * @param checkPin if we want to discard the pieces that are under an absolute pin (meaning that moving that piece will leave the king under check) pass true, otherwise pass false.
	 * @return an array containing the positions where the pieces with acces to that square are (according with the given parameters).
	 */
	private Position[] pieceSearch(boolean recursive, Position position, ChessPiece kind, Color color, int yIncrement[], int xIncrement[], boolean checkPin){
		int countIncr=0;		
		Position positionTest = new Position(position);		
		List<Position> positions = new ArrayList<Position>();
		do{
			positionTest = new Position(positionTest.getX()+xIncrement[countIncr],positionTest.getY()+yIncrement[countIncr]);
			if(!positionTest.isInRange()){
				positionTest = new Position(position);
				countIncr++;				
			}else{
				Piece piece = this.getPiece(positionTest);			
				if(piece!=null){
					if((piece.getKind()==kind && piece.getColor()==color) && (kind==ChessPiece.KING || !checkPin || !isPieceUnderAbsolutePin(positionTest,position))){
						positions.add(positionTest);						
					}					
					positionTest = new Position(position);
					countIncr++;										
				}else if(!recursive){
					positionTest = new Position(position);					
					countIncr++;
				}
			}
		}while(countIncr<yIncrement.length);		
		Position[] res = new Position[positions.size()];
		positions.toArray(res);		
		return res;
	}
	
	/**
	 * Due to the fact that pawns move in a very different way of the other pieces this function is necessary, is the equivalent of "pieceSearch" but concretely for pawns.
	 * 
	 * @param position  square where we are searching the access to
	 * @param color color of the pawns that we are searching (this value can not be null)
	 * @param xEnPassant if in the last move there was a pawn on passant, the column of that pawn must be specified here, otherwise -1 value will be expected
	 * @param checkPin if we want to discard the pawns that are under an absolute pin (meaning that moving that pawn will leave the king under check) pass true, otherwise pass false.
	 * @return an array containing the positions where the pawns with acces to that square are (according with the given parameters).
	 */
	private Position[] pawnSearch(Position position, Color color, int xEnPassant, boolean checkPin){
		int yIncr = (color==Color.WHITE)?-1:1;
		if((position.getY()<2 && color==Color.WHITE) || (position.getY()>5 && color==Color.BLACK))
			return new Position[0];
		ArrayList<Position> positions  = new ArrayList<Position>();
		Piece piece = this.getPiece(position);
		Piece searchPiece=null;
		int passantRank = (color== Color.WHITE)?5:2;
		if(piece==null && !(passantRank==position.getY() && xEnPassant==position.getX())){
			searchPiece = this.getPiece(position.getX(), position.getY()+yIncr);			
			if(searchPiece!=null && searchPiece.getKind()==ChessPiece.PAWN && searchPiece.getColor()==color && (!checkPin || !isPieceUnderAbsolutePin(new Position(position.getX(), position.getY()+yIncr),position))){
				positions.add(new Position(position.getX(), position.getY()+yIncr));
			}else{
				int posRank = (color== Color.WHITE)?3:4;
				if(posRank==position.getY() && searchPiece==null){
					searchPiece = this.getPiece(position.getX(), position.getY()+(yIncr*2));
					if(searchPiece!=null && searchPiece.getKind()==ChessPiece.PAWN && searchPiece.getColor()==color && (!checkPin || !isPieceUnderAbsolutePin(new Position(position.getX(), position.getY()+(yIncr*2)),position))){
						positions.add(new Position(position.getX(), position.getY()+(yIncr*2)));
					}
				}
			}
		}else if((passantRank==position.getY() && xEnPassant==position.getX()) || piece.getColor()!=color){
			for(int i=0;i<2;i++){
				Position possiblePosition = new Position((i==0)?position.getX()+1:position.getX()-1, position.getY()+yIncr);
				if(possiblePosition.isInRange()){
					searchPiece = this.getPiece(possiblePosition);
					if(searchPiece!=null && searchPiece.getKind()== ChessPiece.PAWN && searchPiece.getColor()==color && (!checkPin || !isPieceUnderAbsolutePin(possiblePosition, position))){
						positions.add(possiblePosition);
					}
				}
				
			}			
		}
		Position[] res = new Position[positions.size()];
		positions.toArray(res);		
		return res;
	}
	
	
	/**
	 * Use this function if you want to know if the last registered move was a check or a check-mate. 
	 * 
	 * @param attackingSide The side that made the last move
	 * @param xEnPassant if the last move was a pawn on passant the column of that pawn must be specified in 
	 * this parameter, otherwise -1 is expected.
	 * @return a -1 means is not check, 1 means is check, 2 means is check-mate.
	 */
	public int isCheck(Color attackingSide, int xEnPassant){
		// hem de mirar si el rei del color que no és el torn està en escac o en escac i mat		
		int check=-1;		
		Color deffendingSide = (attackingSide==Color.WHITE)?Color.BLACK:Color.WHITE;
		Position kingPos = findKing(deffendingSide);		
		Position[] checkingPieces = getPiecesWithAccesToPosition(kingPos,null,attackingSide,-1,false);		
		if(checkingPieces.length>0)
			check= (isMate(kingPos,attackingSide,checkingPieces,xEnPassant))?2:1;		
		return check;
	}
	
	
	/**
	 * If the last move was check, this function will check if it was mate or not.
	 * 
	 * @param kingPosition Position of the king under check
	 * @param attackingSide Color of the attaking side
	 * @param checkingPieces array with the pieces that are checking the king.
	 * @param xEnPassant informs if there is a pawn of the attaking side on passant
	 * @return a boolean value that indicates if it's check mate or not.
	 */
	private boolean isMate(Position kingPosition,Color attackingSide,Position[] checkingPieces, int xEnPassant){
		boolean mate =false;
		Color deffendingSide = (attackingSide==Color.WHITE)?Color.BLACK:Color.WHITE;		
		int nKingAvailableSquares=kingAvailableSquares(kingPosition).length;
		//Si el rei té caselles a on moure ja no cal que mirem res més, no és escac i mat
		if(nKingAvailableSquares==0){
			//si el rei està sent atacat per 2 peces a l'hora i no té caselles on moure és escac i mat, ja que en
			//una sola jugada no es poden bloquejar o neutralitar 2 atacants a l'hora
			if(checkingPieces.length>1){
				mate=true;
			}else{
				//si el rei està sent atacat per una sola peça, primer mirarem si aquella peça pot ser atacada per alguna de les nostres
				Position[] attackDefenders= getPiecesWithAccesToPosition(checkingPieces[0],null,deffendingSide,-1,true);
				//en cas de que no poguem capturar a l'atacant, haurem de mirar si podem bloquejar l'atac 
				if((attackDefenders.length==0) || (attackDefenders.length==1 && this.getPiece(attackDefenders[0]).getKind()== ChessPiece.KING)){
					//si la peça que ataca al rei és un peo, haurem de mirar si aquell peo pot ser capturat al pas. 
					if(this.getPiece(checkingPieces[0]).getKind()==ChessPiece.PAWN && checkingPieces[0].getX()== xEnPassant){
						int yIncr = (attackingSide==Color.BLACK)?1:-1;
						attackDefenders =  getPiecesWithAccesToPosition(new Position(checkingPieces[0].getX(),checkingPieces[0].getY()+yIncr),ChessPiece.PAWN,deffendingSide,xEnPassant,true);
						if(attackDefenders.length==0)
							mate=true;
					}else if(!canBlockAttacker(kingPosition,checkingPieces[0]))
						mate=true;
				}
			}			
		}
		return mate;
	}
	
	/**
	 * In order to know if it's check mate or not, sometimes we will have to check if it's possible to block the attaking piece.
	 * This function will provide that information.
	 * 
	 * @param kingPosition Position of the king under check
	 * @param attackerPosition Position of the piece attaking the king
	 * @return a boolean value that indicates if the attack can be blocked.
	 */
	private boolean canBlockAttacker(Position kingPosition, Position attackerPosition){
		boolean findBlocker = false;		
		Color deffendingSide = this.getPiece(kingPosition).getColor();		
		if(this.getPiece(attackerPosition).getKind() != ChessPiece.KNIGHT){
			int xIncrement=attackerPosition.getX()-kingPosition.getX();
			int yIncrement=attackerPosition.getY()-kingPosition.getY();
			if(xIncrement!=0)
				xIncrement=(xIncrement>0)?1:-1;
			if(yIncrement!=0)
				yIncrement=(yIncrement>0)?1:-1;			
			Position checkPossibleBlockers = new Position(kingPosition.getX()+xIncrement,kingPosition.getY()+yIncrement);
			while(!checkPossibleBlockers.equals(kingPosition) && !findBlocker) {
				findBlocker = (this.getPiecesWithAccesToPosition(checkPossibleBlockers, null, deffendingSide,-1,true).length>0);
				checkPossibleBlockers = new Position(checkPossibleBlockers.getX()+xIncrement,checkPossibleBlockers.getY()+yIncrement);
			}			
		}		
		return findBlocker;
	}
	
	/**
	 * In order to know if it's check mate the first thing that we should do is to check if the king under check has 
	 * any available squares where to move, this function provides this inforamtion.
	 * 
	 * @param kingPosition Position of the king under check
	 * @return a boolean value indicating if the king has any available squares.
	 */
	private Position[] kingAvailableSquares(Position kingPosition){
		Piece king = this.getPiece(kingPosition);		
		int countIncr=0;				
		List<Position> squares = new ArrayList<Position>();
		
		int[] xIncrement = {0,0,1,1,1,-1,-1,-1}; 
		int[] yIncrement = {1,-1,0,1,-1,0,1,-1};
		Position positionTest;
		
		do{
			positionTest= new Position(kingPosition.getX() +xIncrement[countIncr] , kingPosition.getY() +yIncrement[countIncr]);						
			if(!positionTest.isInRange()){				
				countIncr++;				
			}else{
				Piece piece = this.getPiece(positionTest);			
				if(piece==null || piece.getColor()!= king.getColor()){
					this.setPiece(positionTest, king);
					if(getPiecesWithAccesToPosition(positionTest,null,(king.getColor()==Color.WHITE)?Color.BLACK:Color.WHITE,-1,false).length==0)
						squares.add(positionTest);					
					this.setPiece(positionTest, piece);
				}				
				countIncr++;
			}
		}while(countIncr<yIncrement.length);
		Position[] res = new Position[squares.size()];
		squares.toArray(res);		
		return res;		
	}
	
	
	/** 
	 * Retrives the position of the king of the indicated color
	 * 
	 * @param color color of the king that we are searching
	 * @return position of that king
	 */
	private Position findKing(Color color){
		Position pos=null;
		int i=0;
		Piece piece;
		do{
			piece = this.getPiece(i/8, i%8);
			if(piece!=null && piece.getKind()== ChessPiece.KING && piece.getColor()==color){
				pos = new Position(i/8, i%8);
			}
			i++;
		}while(pos==null && i<64);
		return pos;
	}
	
	/**
	 * Checks if a move is generating a pawn on passant
	 * 
	 * @param from square from where the piece is moved
	 * @param to square to where the piece is moved
	 * @return a boolean value indicationg if that move has generated a on passant pawn
	 */
	public boolean checkMoveEnPassant(Position from, Position to){		
		Piece piece = this.getPiece(from);
		if(piece==null || piece.getKind()!= ChessPiece.PAWN)
			return false;
		Color color = piece.getColor();
		if((from.getX()-to.getX())!=0 || Math.abs(from.getY()-to.getY())!=2)
			return false;
		Position possiblePawnPos= new Position(to.getX()+1, to.getY());
		Piece posPawn=null;
		if(possiblePawnPos.isInRange()){
			posPawn=this.getPiece(possiblePawnPos);
			if(posPawn!=null && posPawn.getKind()== ChessPiece.PAWN && posPawn.getColor()!=color)
				return true;
		}		
		possiblePawnPos= new Position(to.getX()-1, to.getY());
		posPawn=null;
		if(possiblePawnPos.isInRange()){
			posPawn=this.getPiece(possiblePawnPos);
			if(posPawn!=null && posPawn.getKind()== ChessPiece.PAWN && posPawn.getColor()!=color)
				return true;
		}		
		return false;		
	}
	
	
	/**
	 * Checks if a piece is under an absolute pin, meaning that moving the piece to a concrete square would leave the own king under check.
	 * 
	 * @param piecePosition Position of the piece that we want to check out
	 * @param pieceDestination Position of where the piece wanst to be moved (even if a piece is under an absolute pin, that piece will be able to move in between the squares of the pinning line)
	 * @return a boolean value indicating if the piece is under an absolute pin.
	 */
	public boolean isPieceUnderAbsolutePin(Position piecePosition, Position pieceDestination){
		Color colorPiece = this.getPiece(piecePosition).getColor();
		Position kingPosition = this.findKing(colorPiece);
		boolean absolutPin=false;		
		int difX = kingPosition.getX() - piecePosition.getX();
		int difY =kingPosition.getY() - piecePosition.getY();
		if(difX==0 || difY==0 || Math.abs(difX) == Math.abs(difY)){
			int xIncrement=0;
			int yIncrement=0;
			if(difX!=0)
				xIncrement=(difX>0)?1:-1;
			if(difY!=0)
				yIncrement=(difY>0)?1:-1;
			boolean pieceInBetween = false;
			Position posInBetween = new Position(piecePosition.getX()+xIncrement,piecePosition.getY()+yIncrement);
			while(!pieceInBetween && !posInBetween.equals(kingPosition)) {
				if(this.getPiece(posInBetween)!=null || pieceDestination.equals(posInBetween))
					pieceInBetween = true;
				 posInBetween = new Position(posInBetween.getX()+xIncrement,posInBetween.getY()+yIncrement);
			}
			if(!pieceInBetween){
				xIncrement=xIncrement*-1;
				yIncrement=yIncrement*-1;				
				ChessPiece attackerPinnig = null;
				boolean pieceFound=false;
				Position posAttacker = new Position(piecePosition.getX()+xIncrement,piecePosition.getY()+yIncrement);
				while(!pieceFound && posAttacker.isInRange()) {
					Piece piece = this.getPiece(posAttacker);
					if(posAttacker.equals(pieceDestination)){
						pieceFound = true;
					}else if(piece!=null){
						pieceFound = true;
						if(piece.getColor() != colorPiece && (piece.getKind()== ChessPiece.BISHOP || piece.getKind()== ChessPiece.QUEEN || piece.getKind()== ChessPiece.ROOK)){							
							attackerPinnig= piece.getKind();
							absolutPin=true;
							if(attackerPinnig== ChessPiece.ROOK && difX!=0 && difY!=0)
								absolutPin=false;
							if(attackerPinnig== ChessPiece.BISHOP && (difX==0 || difY==0))
								absolutPin=false;
						}
					}
					posAttacker = new Position(posAttacker.getX()+xIncrement,posAttacker.getY()+yIncrement);
				}				
			}
		}		
		return absolutPin;
	}
	
	
	/**
	 * Useful function for debuging, allows to print the position of the board in a very simple view. 
	 * @param fromWhitePOV indicates if the board has to be printed form white's or black's perspective.
	 */
	public void printIt(boolean fromWhitePOV){
		Piece piece=null;
		String p="";
		int posy=0;
		int posx=0;		
		
		for(int y=7;y>-1;y--){
			for(int x=0;x<8;x++){
				posx=(fromWhitePOV)?x:Math.abs(x-7);
				posy=(fromWhitePOV)?y:Math.abs(y-7);
				piece = this.getPiece(posx,posy);										
					if(piece==null){
						p=String.valueOf((char)176);
						p = " " + p + " ";
					}else{					
						switch (piece.getKind()){
							case BISHOP:
								p=" a ";
								break;
							case KING:
								p=" r ";
								break;
							case KNIGHT:
								p=" c ";
								break;
							case PAWN:
								p=" p ";
								break;
							case QUEEN:
								p=" d ";
								break;
							case ROOK:
								p=" t ";
								break;
						}	
					}				
				System.out.print(p);
			}
			System.out.println("");
		}		
	}
	
	public String getFEN(){
		StringBuilder sb = new StringBuilder();		
		int countNulls=0;
		Piece piece =null;
		for(int y=7;y>-1;y--){
			for(int x=0;x<8;x++){
				piece = this.getPiece(x, y);
				if(piece==null){
					countNulls++;
				}else{
					if(countNulls>0)
						sb.append(countNulls);
					sb.append(Util.getFENInitial(piece));
					countNulls=0;
				}
			}
			if(countNulls>0)
				sb.append(countNulls);
			sb.append('/');
			countNulls=0;
		}
		sb.deleteCharAt(sb.length()-1);
		sb.append(' ');
		
		if(this.turn== Color.BLACK){
			sb.append('b');
		}else{
			sb.append('w');
		}
		sb.append(' ');
		
		if(this.whiteCastling==0 && this.blackCastling==0){
			sb.append('-');
		}else{
			if(this.whiteCastling>0){
				switch (this.whiteCastling){
				case 1:				
					sb.append('K');
					break;
				case 2:				
					sb.append('Q');
					break;
				case 3:				
					sb.append("KQ");
					break;				
				}			 
			}
			if(this.blackCastling>0){
				switch (this.blackCastling){
				case 1:				
					sb.append('k');
					break;
				case 2:				
					sb.append('q');
					break;
				case 3:				
					sb.append("kq");
					break;				
				}			 
			}
		}
		sb.append(' ');		
		
		if(this.enPassant==-1){
			sb.append('-');
		}else{
			sb.append(Util.getStrFromPosition(new Position(this.enPassant, (this.turn==Color.BLACK)?2:5)));
		}
		sb.append(' ');
		sb.append(this.halfMoves);
		sb.append(' ');
		sb.append(this.fullMove);
				
		return sb.toString();
	}
	
	/**
	 * Given a concrete position retrieves the piece in there.
	 * @param pos Position of the piece
	 * @return the piece in the given position
	 */
	public Piece getPiece(Position pos){
		return board[pos.getX()][pos.getY()];
	}
	/**
	 * Given a concrete position retrieves the piece in there.
	 * @param x x Position of the piece
	 * @param y y Position of the piece
	 * @return the piece in the given position
	 */
	public Piece getPiece(int x, int y){
		return board[x][y];
	}	
	
	/**
	 * Given a concrete position sets a the piece in there.
	 * @param pos Position where to set a piece
	 * @param piece Piece to be setted up
	 */
	public void setPiece(Position pos, Piece piece){
		board[pos.getX()][pos.getY()]=piece;
	}	
	/**
	 * Given a concrete position sets a the piece in there.
	 * @param x x Position where to set a piece
	 * @param y y Position where to set a piece
	 * @param piece Piece to be setted up
	 */
	public void setPiece(int x, int y, Piece piece){
		board[x][y]=piece;
	}	
	/**	 
	 * @return returns an array representating the concrete position of the board.
	 */
	public Piece[][] getBoard() {
		return board;
	}
}
